import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;

class DemoPerson extends Object implements Serializable {
    String name;
    char gender;
    int age;
    String addr;
    DemoPerson() {
        name = "";
        gender = 'M';
        age = 0;
        addr = "";
    }

    DemoPerson(String nameInput, char genderInput, int ageInput, String addrInput) {
        name = nameInput;
        gender = genderInput;
        age = ageInput;
        addr = addrInput;
    }

    @Override
    public String toString() {
        return String.format("DemoPerson: name:%s,gender:%c,age:%d,addr:%s", name, gender, age, addr);
    }
}

// https://blog.csdn.net/qq_62414755/article/details/125886742
//方法一：若类实现了serializable接口，则可以通过objectOutputstream和objectinputstream默认的序列化和反序列化方式，对非transient的实例变量进行序列化和反序列化。
//方法二：若类实现了serializable接口，并且定义了writeObject(objectOutputStream out)和 readObject(objectinputStream in)方法，则可以直接调用类的两种方法进行序列化和反序列化。
//方法三：若类实现了Externalizable接口，则必须实现readExternal(Objectinput in)和writeExternal(Objectoutput out)方法进行序列化和反序列化。

class DemoStudent extends DemoPerson implements Serializable {
    String school;
    String grade;
    String classRoom;
    transient HashMap<String, Object> extentdInfo; // transient关键字表示有理的，被修饰的数据不能进行序列化

    DemoStudent() {
        super();

        school = "";
        grade = "";
        classRoom = "";
    }

    DemoStudent(String nameInput, char genderInput, int ageInput, String addrInput, String schoolInput, String gradeInput, String classRoomInput) {
        name = nameInput;
        gender = genderInput;
        age = ageInput;
        addr = addrInput;

        school = schoolInput;
        grade = gradeInput;
        classRoom = classRoomInput;
    }

    @Override
    public String toString() {
        return String.format("DemoStudent: name:%s,gender:%c,age:%d,addr:%s,school:%s,grade:%s,classRoom:%s", name, gender, age, addr, school, grade, classRoom);
    }

    private void writeString2OutputStream(ObjectOutputStream out, String str2Write) throws IOException {
        try {
            // 写入 str2Write 长度
            byte[] strBytes = str2Write.getBytes(StandardCharsets.UTF_8);
            out.writeInt(strBytes.length);
            // 写入 str2Write 字节数据
            out.write(strBytes);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    protected void writeObject(ObjectOutputStream out) throws IOException {
        try {
            // 写入 gender 和 age
            out.writeChar(this.gender);
            out.writeInt(this.age);

            // 写入字符串
            this.writeString2OutputStream(out, this.name);
            this.writeString2OutputStream(out, this.addr);
            this.writeString2OutputStream(out, this.school);
            this.writeString2OutputStream(out, this.grade);
            this.writeString2OutputStream(out, this.classRoom);

            // 已经向 输出流 dos 中 写入了多少byte数据
            //System.out.println("writePersonIntoStream end, out.size = "+out.size());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String readStringFromInput(ObjectInputStream in) throws IOException {
        String strRtn = null;
        try {
            // 读取 str byte 长度
            int byteLen = in.readInt();
            //System.out.println("readStringFromInput, byteLen = "+byteLen);

            // 按byteLen 准备byte 数组
            byte[] nameBytes = new byte[byteLen];
            in.read(nameBytes);
            strRtn = new String(nameBytes, StandardCharsets.UTF_8);
            //System.out.println("readStringFromInput, strRtn = "+strRtn);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return strRtn;
    }

    protected void readObject(ObjectInputStream input) throws IOException {
        try {
            // 写入 gender 和 age
            this.gender = input.readChar();
            this.age = input.readInt();

            // 写入字符串
            this.name = this.readStringFromInput(input);
            this.addr = this.readStringFromInput(input);
            this.school = this.readStringFromInput(input);
            this.grade = this.readStringFromInput(input);
            this.classRoom = this.readStringFromInput(input);

            // 已经向 输出流 dos 中 写入了多少byte数据
            //System.out.println("writePersonIntoStream end, out.size = "+out.());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class DemoTeacher extends DemoPerson implements Externalizable {
    String school;
    String jobTitle;

    // Externalizable 要求 默认构造函数必须有，而且必须是public
    public DemoTeacher() {
        super();

        school = "";
        jobTitle = "";
    }

    DemoTeacher(String nameInput, char genderInput, int ageInput, String addrInput, String schoolInput, String jobTitleInput) {
        name = nameInput;
        gender = genderInput;
        age = ageInput;
        addr = addrInput;

        school = schoolInput;
        jobTitle = jobTitleInput;
    }

    private void writeString2Output(ObjectOutput out, String str2Write) throws IOException {
        try {
            // 写入 str2Write 长度
            byte[] strBytes = str2Write.getBytes(StandardCharsets.UTF_8);
            out.writeInt(strBytes.length);
            // 写入 str2Write 字节数据
            out.write(strBytes);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        try {
            // 写入 gender 和 age
            out.writeChar(this.gender);
            out.writeInt(this.age);

            // 写入字符串
            this.writeString2Output(out, this.name);
            this.writeString2Output(out, this.addr);
            this.writeString2Output(out, this.school);
            this.writeString2Output(out, this.jobTitle);

            // 已经向 输出流 dos 中 写入了多少byte数据
            //System.out.println("writePersonIntoStream end, out.size = "+out.());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String readStringFromInput(ObjectInput in) throws IOException {
        String strRtn = null;
        try {
            // 读取 str byte 长度
            int byteLen = in.readInt();
            //System.out.println("readStringFromInput, byteLen = "+byteLen);

            // 按byteLen 准备byte 数组
            byte[] nameBytes = new byte[byteLen];
            in.read(nameBytes);
            strRtn = new String(nameBytes, StandardCharsets.UTF_8);
            //System.out.println("readStringFromInput, strRtn = "+strRtn);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return strRtn;
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.gender = in.readChar();
        this.age = in.readInt();

        this.name = this.readStringFromInput(in);
        this.addr = this.readStringFromInput(in);
        this.school = this.readStringFromInput(in);
        this.jobTitle = this.readStringFromInput(in);
    }

    @Override
    public String toString() {
        return String.format("DemoTeacher: name:%s,gender:%c,age:%d,addr:%s,school:%s,jobTitle:%s", name, gender, age, addr, school, jobTitle);
    }
}

public class OODemo {
    protected static void demoLogic() {
        DateTimeDemo.logTs("OODemo");
    }
}
